<template>
  <div id="main">
    <img alt="Vue logo" src="./assets/logo.png" />
    <!-- ref -->
    <!-- <div>{{ count }}</div>
  <div>{{ double }}</div>
  <button @click="increase">点击+1</button> -->

    <!-- reactive -->
    <!-- <div>{{ data.count }}</div>
  <div>{{ data.double }}</div>
  <button @click="data.increase">点击+1</button> -->

    <!-- reactive简化版 -->
    <div>{{ count }}</div>
    <div>{{ double }}</div>
    <button @click="increase">点击+1</button>

    <ul>
      <li v-for="number in numbers" :key="number">{{ number }}</li>
    </ul>
    <h1>{{ person.name }}</h1>

    <button @click="updateGreeting">点击updateTitle</button>

    <h1>X:{{ x }} Y: {{ y }}</h1>
    <h1 v-if="loading">loading..!</h1>
    <!-- <img v-if="loaded" :src="result?.message" /> -->
    <img v-if="loaded && result" :src="result[0].url" />

    <!-- vue3新出的emit自定义组件的事件 -->
    <button @click="openModal">Open Modal</button>
    <!-- <modal /> -->
    <modal :isOpen="modalIsOpen" @close-modal="onModalClose">My Modal !!!</modal>

    <!-- Suspense的用法 --><!-- 加载单个异步组件 --> <!-- 加载多个异步组件时，会等所有异步组件都加载完毕再一块展示 -->

    <!-- 通过onErrorCaptured来捕获组件的异常，并保存在error中，再展示出来 -->
    <p>{{ error }}</p>

    <Suspense>
      <template #default>
        <div>
          <async-show />
          <dog-show />
        </div>
      </template>
      <template #fallback>
        <!-- 默认加载Loading ! ...，3s后展示async-show里的result,即 42 -->
        <h1>Loading ! ...</h1>
      </template>
    </Suspense>

    <button @click="changeLang('en')">英文</button>
    <button @click="changeLang('ch')">中文</button>

  </div>
</template>

<script lang="ts">
import {
  computed,
  defineComponent,
  onMounted,
  onUpdated,
  reactive,
  ref,
  toRefs,
  onRenderTriggered,
  watch,
  watchEffect,
  onUnmounted,
  onErrorCaptured,
  provide
} from "vue";
interface DataProps {
  count: number;
  increase: () => void;
  double: number;
  numbers: number[];
  person: { name?: string };
}
import useMousePosition from "@/hooks/useMousePosition";
import useURLLoader from "./hooks/useURLLoader";
import modal from "./components/Modal.vue";
import AsyncShow from "./components/AsyncShow.vue";
import DogShow from "./components/DogShow.vue";
interface DogResult {
  message: string;
  status: string;
}
interface CatResult {
  id: string;
  url: string;
  width: number;
  height: number;
}

export default defineComponent({
  name: "App",
  components: {
    modal, // 注册 Modal 组件
    AsyncShow,
    DogShow
  },
  setup() {
    // onMounted(() => {
    //   console.log("onMounted");
    // });
    onUpdated(() => {
      console.log("onUpdated");
    });
    onRenderTriggered((event) => {
      console.log(event, "event");
    });
    //1、ref
    // const count = ref(0);
    // const increase = () => {
    //   count.value++;
    // };
    // const double = computed(() => count.value * 2);

    //2、reactive
    const data: DataProps = reactive({
      count: 0,
      increase: () => {
        data.count++;
      },
      double: computed(() => data.count * 2),
      numbers: [0, 1, 2],
      person: {},
    });
    data.numbers[0] = 5;
    data.person.name = "vip"; //属性只有在对象内才是响应式的，若是要解构出来使用需要用toRefs等转换

    //3、监听
    const greeting = ref("");
    const updateGreeting = () => {
      greeting.value = greeting.value + "hello";
    };
    //监听单个
    // watch(greeting, (newVal, oldVal) => {
    //   console.log(newVal, oldVal); //greeting的值
    //   document.title = greeting.value;
    //   console.log(document.title, "document.title");
    // });
    //监听多个
    // watch([greeting, data], (newVal, oldVal) => {
    //   console.log(newVal, "newVal"); //greeting和data组成的数组 [greeting,data]
    //   console.log(oldVal, "oldVal");
    //   document.title = greeting.value + data.count;
    //   console.log(document.title, "document.title");
    // });

    //监控对象的某个属性-错误写法- Vue 的响应式系统对对象的属性访问和修改有一些限制-watch 的监听目标必须是响应式数据-data是响应式对象，但是data.count本身不是响应式属性
    watch([greeting, data.count], (newVal, oldVal) => {
      console.log(newVal, "newVal"); //['hello', undefined] 'newVal'
      console.log(oldVal, "oldVal"); //['', undefined] 'oldVal'
    });
    //监控对象的某个属性-正确写法1：使用 getter 函数监听 data.count
    watch([greeting, () => data.count], (newVal, oldVal) => {
      console.log(newVal, "newVal"); //['hello', undefined] 'newVal'
      console.log(oldVal, "oldVal"); //['', undefined] 'oldVal'
    });
    //监控对象的某个属性-正确写法2：使用 watchEffect 自动追踪依赖
    watchEffect(() => {
      console.log(data.count, "count changed");
    });

    //4、鼠标追踪器---封装成全局hook函数
    // const x = ref(0);
    // const y = ref(0);
    // const updateMouse = (e: MouseEvent) => {
    //   x.value = e.pageX;
    //   y.value = e.pageY;
    // };
    // onMounted(() => {
    //   document.addEventListener("click", updateMouse);
    // });
    // onUnmounted(() => {
    //   document.removeEventListener("click", updateMouse);
    // });
    const { x, y } = useMousePosition();

    // const { result, loading, loaded } = useURLLoader<DogResult>(
    //   "https://dog.ceo/api/breeds/image/random"
    // );

    const { result, loading, loaded } = useURLLoader<CatResult[]>(
      "https://api.thecatapi.com/v1/images/search?limit=10"
    );

    watch(result, () => {
      if (result.value) {
        console.log(result.value[0].id, "result");
      }
    });

    const modalIsOpen = ref(false);
    const openModal = () => {
      modalIsOpen.value = true;
    }
    const onModalClose = () => {
      modalIsOpen.value = false;
    }

    const error = ref(null)
    onErrorCaptured((e: any) => {
      // 只会在组件树中发生错误时被调用。如果你的代码中没有抛出错误，它自然不会执行
      console.log(e, 'e');
      error.value = e
      return true
    })

    //provide 提供数据  key-value
    provide('lang', 'ch')//非响应式

    const lang = ref('en');//响应式
    provide('langValue', lang);

    const changeLang = (type: string) => {
      lang.value = type;
    }

    return {
      // count,
      // double,
      // increase, //ref
      // data,  //reactive
      // ...data, // reactive简化版 --- 将对象解构出来可以直接用其属性名和方法名，但是将属性从响应式对象里直接取出来，就不再是响应式属性和方法了，这时候属性和方法不起作用，页面数据不会更新，点击方法也无效，需要用toRefs
      ...toRefs(data), //先把对象里的属性和方法都转换成响应式的，再解构出来
      greeting,
      updateGreeting,
      // x,
      // y,
      x,
      y,
      result,
      loading,
      loaded,
      modalIsOpen,
      openModal,
      onModalClose,
      error,
      changeLang
    };
  },
});
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
